package service

import (
	"context"
	"errors"
	"fmt"
	"github.com/go-kratos/kratos/v2/log"
	"github.com/gogf/gf/util/gconv"
	"go.opentelemetry.io/otel"
	"go.opentelemetry.io/otel/attribute"
	"go.opentelemetry.io/otel/trace"
	amount_v1 "gorm_transaction/api/Amount1Server/v1"
	"gorm_transaction/internal/biz"
	"runtime/debug"
)

type Amount1Service struct {
	amount_v1.UnimplementedAmount1ServiceServer

	log        *log.Helper
	cellBiz    *biz.CellBizStruct
	amount1Biz *biz.Amount1BizStruct
	staffBiz   *biz.StaffBizStruct
}

func NewAmount1Service(bz *biz.Amount1BizStruct, cellBiz *biz.CellBizStruct, staffBiz *biz.StaffBizStruct, logger log.Logger) *Amount1Service {
	return &Amount1Service{
		amount1Biz: bz,
		cellBiz:    cellBiz,
		staffBiz:   staffBiz,
		log:        log.NewHelper(logger),
	}
}

func (a *Amount1Service) AddOrder(ctx context.Context, req *amount_v1.AddOrderRequest) (*amount_v1.Empty, error) {
	return a.amount1Biz.AddOrder(ctx, req)
}

func (a *Amount1Service) TransOutOrder(ctx context.Context, req *amount_v1.TransOutOrderRequest) (*amount_v1.Empty, error) {
	return a.amount1Biz.TransOutOrder(ctx, req)
}

func (a *Amount1Service) TransOutOrderCompensate(ctx context.Context, req *amount_v1.TransOutOrderCompensateRequest) (*amount_v1.Empty, error) {
	return a.amount1Biz.TransOutOrderCompensate(ctx, req)
}

func (a *Amount1Service) GetOrderMains(ctx context.Context, req *amount_v1.GetOrderMainsReq) (ret *amount_v1.GetOrderMainsReply, errRet error) {
	ctx, span := otel.Tracer("Service").Start(ctx, "GetOrderMainsService", trace.WithSpanKind(trace.SpanKindProducer))
	defer func() {
		if err := recover(); err != nil {
			// trace
			stackInfo := string(debug.Stack())
			span.SetAttributes(attribute.String("errStack", stackInfo))
			// log
			errMsg := fmt.Sprintf("%v方法中发生了panic errStack: %v", "GetOrderMainsService", stackInfo)
			a.log.WithContext(ctx).Error(errMsg)
			// Notice 在业务代码中发生了 panic 后，根据再Error响应中加上捕获panic的标识！
			errRet = errors.New("业务中出现了-Internal Server Error!")
		}
		span.End()
	}()

	// trace
	span.SetAttributes(attribute.String("req", gconv.String(req)))

	// 并发开启事务去查询 —— 根据隔离级别的不同会有不同的问题: https://zhuanlan.zhihu.com/p/29166694
	return a.amount1Biz.GetOrderMains1(ctx, req)

	// Notice 会报错：在事务中开启并发去查询～
	//return a.amount1Biz.GetOrderMains2(ctx, req)
}

func (a *Amount1Service) TransOutOrderBatch(ctx context.Context, req *amount_v1.TransOutOrderBatchRequest) (*amount_v1.Empty, error) {

	// 在事务中并发去执行 update、create 操作 不会报错
	return a.amount1Biz.TransOutOrderBatch(ctx, req)
}

func (a *Amount1Service) BatchEditOrderWithCurrentTx(ctx context.Context, req *amount_v1.TransOutOrderBatchRequest) (*amount_v1.Empty, error) {

	// 并发开启事务操作
	return a.amount1Biz.BatchEditOrderWithCurrentTx(ctx, req)
}

// 从ck中获取数据
func (a *Amount1Service) GetStaffsBySName(ctx context.Context, req *amount_v1.GetStaffsBySNameReq) (ret *amount_v1.GetStaffsBySNameReply, errRet error) {
	ctx, span := otel.Tracer("Service").Start(ctx, "GetStaffsBySNameService", trace.WithSpanKind(trace.SpanKindProducer))
	defer func() {
		if err := recover(); err != nil {
			// trace
			stackInfo := string(debug.Stack())
			span.SetAttributes(attribute.String("errStack", stackInfo))
			// log
			errMsg := fmt.Sprintf("%v方法中发生了panic errStack: %v", "GetStaffsBySNameService", stackInfo)
			a.log.WithContext(ctx).Error(errMsg)
			// Notice 在业务代码中发生了 panic 后，根据再Error响应中加上捕获panic的标识！
			errRet = errors.New("业务中出现了-Internal Server Error!")
		}
		span.End()
	}()

	// trace
	span.SetAttributes(attribute.String("req", gconv.String(req)))

	return a.staffBiz.GetStaffsBySName(ctx, req)
}

// 往ck中批量写入数据
func (a *Amount1Service) CreateStaffs(ctx context.Context, req *amount_v1.CreateStaffsReq) (ret *amount_v1.Empty, errRet error) {
	ctx, span := otel.Tracer("Service").Start(ctx, "CreateStaffsService", trace.WithSpanKind(trace.SpanKindProducer))
	defer func() {
		if err := recover(); err != nil {
			// trace
			stackInfo := string(debug.Stack())
			span.SetAttributes(attribute.String("errStack", stackInfo))
			// log
			errMsg := fmt.Sprintf("%v方法中发生了panic errStack: %v", "CreateStaffsService", stackInfo)
			a.log.WithContext(ctx).Error(errMsg)
			// Notice 在业务代码中发生了 panic 后，根据再Error响应中加上捕获panic的标识！
			errRet = errors.New("业务中出现了-Internal Server Error!")
		}
		span.End()
	}()

	// trace
	span.SetAttributes(attribute.String("req", gconv.String(req)))

	return a.staffBiz.CreateStaffs(ctx, req)
}
